<template>
  <div class="goods-sku">
    <dl v-for="(item,index) in specs" :key="index">
      <dt>{{item.name}}</dt>
      <dd>
       <template v-for="(tag,i) in item.values" :key="i">
             <img @click='toggle(tag, item.values)' :class="{selected:tag.selected,disabled: tag.disabled}" v-if="tag.picture" :src="tag.picture" alt="">
             <span @click='toggle(tag, item.values)' :class="{selected:tag.selected,disabled: tag.disabled}" v-else>{{tag.name}}</span>
       </template>
      </dd>
    </dl>
  </div>
</template>
<script>
// 1 - 引入第三方包,处理数据集合
import powerSet from '@/vendor/power-set.js'

// 2 - 规格分隔符
const spliter = '※'

// A1- 生成数据字典
// 3 - 这也是第三部
const usePathMap = (sku) => {
// 4 -定义一个最终生成的字典
  const result = {}
  sku.forEach(sku => {
    // 5 - 处理无效sku,如果当前的sku没有库存的话,直接return
    if (sku.inventory === 0) return

    // 6 - 后续处理表示有效SKU,获取有效的SKU值:[蓝色, 中国, 20cm]
    const spec = sku.specs.map(item => item.valueName)

    // 7 - 上面已经把sku规格,处理成[蓝色, 中国, 20cm]这样,使用第三方工具计算当个sku规格的笛卡尔集
    const specSet = powerSet(spec)

    // 8 - 循环笛卡尔集数据
    specSet.forEach(item => {
      if (item.length === 0) return
      // 9 - 生产字典的key,把那个符号加在参数之间
      const key = item.join(spliter)

      // 10 - 把key添加到字典中
      if (result[key]) {
        // 11 - 如果字典中已经有了某个key,把sku的id添加进去
        result[key].push(sku.id)
      } else {
        // 12 - 如果字典中没有相关的key,直接添加key,值为sku的id
        result[key] = [sku.id]
      }
    })
  })

  return result
}

// A2- 获取选中的规格数据
const getSelectedValue = (specs) => {
  // A2-1 定义result数组保存选中的数据
  const result = []
  // A2-2 把所有规格参数遍历,item是例如:颜色:黑色,百万 - item.values是黑色,白色
  specs.forEach((item, index) => {
    // A2 -3 把当前选中的例如黑色,赋值给spec(这个就是选中的)
    const spec = item.values.find(tag => tag.selected)
    // A2-4 如果有这个选中的,把这个选中的名字,按照索引添加到result中
    if (spec) {
      result[index] = spec.name
    } else {
      // A2-5 若果没有选中,就把undefined,按照索引添加到result中
      result[index] = undefined
    }
  })
  //   console.log(result, 5245)["黑色", "日本", "30cm"]
  return result
}

// A3- 控制按钮的禁用状态
const updateDisabledStatus = (specs, pathMap) => {
  // A3-1 循环遍历,调用时传过来的specs(所有商品的规格,根据这个渲染出来)
  specs.forEach((item, index) => {
  // A3-2 把选中的数据放在result中,类似于[黑色,中国,10cm]
    const result = getSelectedValue(specs)
    // A3-3 这时的item代表每一项规格,例如: name是产地:vlues里面是[日本,中国]
    item.values.forEach(tag => {
      // A3-4 选中的状态,添加在了tag里面的每一项上了,所以判断,当前项有没有选中
      // A3-5 如果选中了,肯定就不需要禁用了,直接return
      if (tag.selected) return

      // A3-6 如果没有选中状态,把没选中的项的名字,存在result里面,使用索引依次传入
      result[index] = tag.name

      // A3-7 把存有没选中的值的数组filter遍历,加上分隔符※
      const pathKey = result.filter(tag => tag).join(spliter)

      // A3-8 pathKey代表每一个没有选中的值,放在,路径字典里,如果路径字典里没有这个没选中的值,证明这个值没有库存
      // A3-9 如果没有这个值,返回undefined是flase,给他取反变成true,让没有该项值的选项禁用
      // A3-10 标签模板上绑定disabled属性,没有值的数据自然就禁用了
      tag.disabled = !pathMap[pathKey]
    })
  })
}

// A4 -根据传入的skuId初始化规格的选中状态
const initSkuSeletedStatus = (skuId, specs, skus) => {
  // ----------------------------------

  //    skuId表示传入的选中的sku规格的id
  //    specs表示所有的规格数据
  //    skus表示后端返回的原始的库存数据

  // ----------------------------------
  //  6-1 从规格集合中找到和skuId(当前选中的规格)一致的数据,就是当前选中的集合
  const currentSku = skus.find(item => item.id === skuId)

  //  6-2 遍历所有的规格集合,item是每个规格集合
  specs.forEach(item => {
    // 6-3 当前选中的规格集合,中选中的值,再遍历,遍历出来的每一项是[颜色:蓝色]
    currentSku.specs.forEach(tagInfo => {
      // 6 - 4 从每个规格集合中的values中取出的名字和当前选中的名字相等,赋值给tag
      const tag = item.values.find(tag => tag.name === tagInfo.valueName)
      // 6 - 5 如果有这个值,那么当前项被选中
      if (tag) {
        // 该规格需要被选中
        tag.selected = true
      }
    })
  })
}
export default {
  name: 'GoodsSku',
  props: {
    specs: {
      type: Array,
      default: () => []
    },
    skus: {
      type: Array,
      default: () => []
    },
    skuId: {
      type: String,
      default: ''
    }
  },
  setup (props, { emit }) {
    // A1-如果props.skuId有值的话,根据props.skuId初始化规格的选中状态
    if (props.skuId) {
      initSkuSeletedStatus(props.skuId, props.specs, props.skus)
    }
    const pathMap = usePathMap(props.skus)
    updateDisabledStatus(props.specs, pathMap)

    // A-3 切换效果
    const toggle = (tag, list) => {
      if (tag.disabled) return
      // A-3-1处理当前点击的标签是否选中
      tag.selected = !tag.selected

      // A-3-1处理点击当前标签之外的其他标签的情况
      list.forEach(item => {
        if (item.name !== tag.name) {
          item.selected = false
        }
      })
      // A-3-1点击按钮时更新禁用状态
      updateDisabledStatus(props.specs, pathMap)

      // -------------------------------------------------------

      // A4-获取选中规格所有的值,传递给父组件
      // A4-1 如果选中了所有的规格，就传递正常的数据 skuId 价格  原价  库存 规格文字
      // A4-2 如果没有全部选中，就传递空对象 {}

      // A4-3 getSelectedValues函数中传入值,会返回选中的数据,
      // A4-4 筛选出不为空的数据赋值到selectedValues(当前选中信息)例如:["黑色", "中国", "30cm"]
      const selectedValues = getSelectedValue(props.specs).filter(item => item)

      // A4-4 如果当前选中信息的长度等于传过来的specs长度,证明规格全部选中,发送result
      if (selectedValues.length === props.specs.length) {
        // A4-5 这个对象是需要传给父亲的值的集合
        const result = {}

        // A4-6 在当前选中的信息中加入※号,组成路径字典的要是(当前的选中规格)
        const pathKey = selectedValues.join(spliter)

        // A4-7  因为如果都选中了,key后面只有一个id,所以说[0]就是那个id
        const skuId = pathMap[pathKey][0]

        // A4-8 根据skuId从skus(所有的规格)中找到和当前规格id相等的规格,拿到该规格的详细数据
        const skuInfo = props.skus.find(item => item.id === skuId)

        // A4-9 把当前选中的规格信息,里面的值赋值给发送给父组件的对象
        result.skuId = skuId
        result.price = skuInfo.price
        result.oldPrice = skuInfo.oldPrice
        result.inventory = skuInfo.inventory

        // A4-10 拼接规格数据-例如-颜色:黑色 产地:日本 规格:30cm
        result.specsText = skuInfo.specs.reduce((result, item) => result + item.name + ':' + item.valueName + ';', '')

        // A4-11 把选中的数据,拼接好的所有数据,发送给父组件
        emit('update-info', result)
      } else {
        // A4-12 规格没有全部选中,发送空对象
        emit('update-info', {})
      }
    }
    return { toggle }
  }

}
</script>
<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;
  &.selected {
    border-color: @xtxColor;
  }
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}
.goods-sku {
  padding-left: 10px;
  padding-top: 20px;
  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;
    dt {
      width: 50px;
      color: #999;
    }
    dd {
      flex: 1;
      color: #666;
      > img {
        width: 50px;
        height: 50px;
        .sku-state-mixin ();
      }
      > span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>
